/* ----------------------------------------------------------------------------

	pax.widget.menu.js Copyright (C) 2002, 2004, 2005, 2006, 2008 Mikkel Bergmann, Pointful

	Licence
	-------
	
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

	See lgpl.txt for licence details

---------------------------------------------------------------------------- */

/*
	Script: pax.widget.menu
		This is a menu widget, that can render in various ways
		
	Author:
		Mikkel Bergmann, <http://www.pointful.com>
		
	Note:
		This widget is not ready for use in production yet.

*/

var pax = pax || {};
pax.widget = pax.widget || {};
pax.widget.menu = pax.widget.menu || {};
pax.widget.menu.dropdown = pax.widget.menu.dropdown || {};
pax.widget.menu.tree = pax.widget.menu.tree || {};
/*
	TODO:
		* Fix the CSS for IE, for both tree and dropdown
*/


/*	Private Method: pax.widget.menu.initModel
	Creates a HTML version of a dropdown menu, from a JSON object
	
	Note: the model is defined as objects within objects, where a string value is an item, and an object value is a submenu
	For example, the following menu will have one item, and one submenu:
	
		var model = {
			'1': 'Item value 1',
			'My submenu': {
				'1': 'Submenu Item value 1',
				'2': 'Submenu Item value 2'
			}
		};
	
	Here is a more extensive example:
	
		var menuModel = {
			'Entre': {
				'0': 'Garlic bread',
				'1': 'Mini Ceasar salad'
			},
			'Mains': {
				'0': 'Roast Lamb',
				'1': 'Grill Chicken',
				'2': 'Sirloin steak',
				'Main specials of the day': {
					'0': 'Fish (ask waiter for details)',
					'1': 'Chicken (a bit like the fish ;o)',
					'Not so specials': {
						'0': 'Yesterdays Tuna melt',
						'1': 'Yesterdays Tuna cheesey',
						'2': 'Yesterdays Tuna gorganzola',
						'3': 'Yesterdays Tuna chunky gorda glut'
					}
				}
			},
			'Specials': {
				'0': 'Tuna melt',
				'1': 'Tuna cheesey',
				'2': 'Tuna gorganzola',
				'3': 'Tuna chunky gorda glut'
			}
		};
		
	Note: simply use hyperlinks to make the items go somewhere
	
*/
pax.widget.menu.initModel = function( model, addAnchor, level ) {
	level = level || 0;
	var tpl = '';
	var styleStr = ( pax.isIe )? ' style="zoom: 1;"': '';
	for( var i in model ) {
		if( typeof( model[i] ) != 'string' ) {
			var menuTitle = ( ( level < 0 || addAnchor ) && i.toLowerCase().indexOf('<a') == -1 )? '<a>' + i + '</a>': i;
			tpl += '<li' + styleStr + '>' + menuTitle + '<ul>'+ pax.widget.menu.initModel( model[i], addAnchor, level + 1 ) + '</ul></li>';
		} else {
			var menuItem = ( model[i].toLowerCase().indexOf('<a') == -1 )? '<a>' + model[i] + '</a>': model[i];
			tpl += '<li' + styleStr + '>' + menuItem + '</li>';
		}
	}
	return tpl;
};


/*	Method: pax.widget.menu.dropdown.init
	Creates a menu from an unordered list
	
	Parameters:
		target - The UL to make into a menu
		args - optional argument object to pass to the menu function, ie: {}
		* type - what type of menu to create, defaults to 'dropdown'
		* vertical - boolean to set orientation of menu, defaults to false, ie: horizontal. This option is only valid for 'dropdown' menu type

	Example:
		(start code)
			<fieldset><legend>dropdown menu</legend>
				<ul id="pax.widget.menu.dropdown.example1">
					<li>Entree
						<ul>
							<li><a>Garlic bread</a></li>
							<li><a>Mini Ceasar salad</a></li>
						</ul>
					</li>
					<li>Mains
						<ul>
							<li><a>Roast Lamb</a></li>
							<li><a>Grill Chicken</a></li>
							<li><a>Sirloin steak</a></li>
							<li>Specials of the day
								<ul>
									<li><a>Fish (ask waiter for details)</a></li>
									<li><a>Chicken (like the fish ;o)</a></li>
								</ul>
							</li>
						</ul>
					</li>
				</ul>
			</fieldset>

			[:.
				pax.widget.menu.dropdown.init( pax.$("pax.widget.menu.dropdown.example1") );
			:]
		(end)
		This will show a simple example of a dropdown menu


	Example:
		(start code)
			<ul id="pax.widget.menu.example2">
				<li>Entree
					<ul>
						<li><a href="#">Garlic bread</a></li>
						<li><a href="#">Oysters kilpatrick</a></li>
						<li><a href="#">Mini Ceasar salad</a></li>
					</ul>
				</li>
				<li>Mains
					<ul>
						<li><a href="#">Roast Lamb</a></li>
						<li><a href="#">Grill Chicken</a></li>
						<li><a href="#">Sirloin steak</a></li>
					</ul>
				</li>
				<li>Dessert
					<ul>
						<li><a href="#">Chocolate mousse</a></li>
						<li><a href="#">Creme brulee</a></li>
						<li>Coffee & tea
							<ul>
								<li><a href="#">Long black</a></li>
								<li><a href="#">Capuccino</a></li>
								<li><a href="#">Latte</a></li>
								<li>Liquor coffes
									<ul>
										<li><a href="#">Kaluah</a></li>
										<li><a href="#">Tia Maria</a></li>
										<li><a href="#">Frangelico</a></li>
										<li><a href="#">Butter Scotch</a></li>
									</ul>
								</li>
								<li><a href="#">English breakfast tea</a></li>
								<li><a href="#">Japanese green tea</a></li>
								<li><a href="#">camomile tea</a></li>
							</ul>
						</li>
						<li><a href="#">Surprise of the day</a></li>
					</ul>
				</li>
			</ul>
			
			[:.
				pax.widget.menu.dropdown.init( pax.$('pax.widget.menu.example2') );
			:]
		(end)
		This renders the UL as a drop down menu
*/
pax.widget.menu.dropdown.init = function( target, args ) {
	args = (typeof(args) != 'undefined' )? args: {};
	var menuIsHorizontal = (typeof(args.vertical) != 'undefined')? ! args.vertical: true;
	
	//	If we have a model, use it as the structure for the menu
	if( args.model ) {
		var tpl = "<ul>" + pax.widget.menu.initModel( args.model, true ) + "</ul>";
		pax.template.render( tpl, { target: target } );
		//	The "actual" target is the first UL in the "target", so we get it.
		var targetUls = target.getElementsByTagName('ul');
		target = targetUls[0];
	}
	
	//	Note: this class name must go on the first UL
	pax.util.addClassName( target, 'paxMenuDropDown' );
	if( menuIsHorizontal )pax.util.swapClassName( target, 'vertical', 'horizontal' );
	else pax.util.swapClassName( target, 'horizontal', 'vertical' );
	
	//	Initialise from the DOM
	var lis = target.getElementsByTagName('li');
	for( var i = 0; i < lis.length; i++ ) {
		var li = lis[i];
		var uls = li.getElementsByTagName('ul');
		if( uls && uls.length != 0 ) {
			var ul = uls[0];
			li.sub = ul;	//	Expando for the sub menu.
			
			//	Workaround for IE - we MUST have layout for this to work
			if( pax.isIe && ! li.currentStyle.hasLayout )li.style.zoom = 1;
			
			//	Bind events
			pax.event.bind( li, 'mouseover', pax.widget.menu.dropdown.showSubMenu );
			pax.event.bind( li, 'mouseout', pax.widget.menu.dropdown.hideSubMenu );

			li.isRootMenu = li.parentNode == target;
			li.isHorizontal = ( menuIsHorizontal && li.isRootMenu );

			//	Make sure this is not the Root menu
			if( li.parentNode != target ) {
				var ahrefs = li.getElementsByTagName('a');
				var ahr = ahrefs[0];
				//	Add the menuSub class name to the anchor
				if( ahr )pax.util.addClassName( ahr, 'menuSub' );
			}
		}
	}
};


/*	Private Method: pax.widget.menu.dropdown.showSubMenu
	Shows a dropdown submenu	
*/
pax.widget.menu.dropdown.showSubMenu = function() {
	pax.util.addClassName( this, 'active' );
	var pos = pax.util.getPosition( this );
	
	if( this.isRootMenu ) {
		this.sub.style.left = ( pos.x + (!this.isHorizontal?pos.width:0) ) + 'px';
		this.sub.style.top =  ( pos.y + (this.isHorizontal?pos.height:0) - (this.isRootMenu? 0: 1) ) + 'px';
	} else {
		this.sub.style.left = this.offsetWidth + 'px';
		this.sub.style.top = this.offsetTop + 'px';
	}
	this.sub.style.visibility = 'visible';
};


/*	Private Method: pax.widget.menu.dropdown.hideSubMenu
	Hides a dropdown submenu	
*/
pax.widget.menu.dropdown.hideSubMenu = function() {	
	this.sub.style.visibility = 'hidden';
	pax.util.removeClassName( this, 'active' );
};


/*	Method: pax.widget.menu.tree.init
	Creates a menu tree from an unordered list
	
	Parameters:
		target - The UL to make into a menu
		args - optional argument object to pass to the menu function, ie: {}
		* type - what type of menu to create, defaults to 'dropdown'
		
	Example:
		(start code)
			<fieldset><legend>Tree menu</legend>
				<ul id="pax.widget.menu.tree.example1">
					<li>Entree
						<ul>
							<li><a>Garlic bread</a></li>
							<li><a>Mini Ceasar salad</a></li>
						</ul>
					</li>
					<li>Mains
						<ul>
							<li><a>Roast Lamb</a></li>
							<li><a>Grill Chicken</a></li>
							<li><a>Sirloin steak</a></li>
							<li>Specials of the day
								<ul>
									<li><a>Fish (ask waiter for details)</a></li>
									<li><a>Chicken (like the fish ;o)</a></li>
								</ul>
							</li>
						</ul>
					</li>
				</ul>
			</fieldset>

			[:.
				pax.widget.menu.tree.init( pax.$("pax.widget.menu.tree.example1") );
			:]
		(end)
		This will show a simple example of a tree menu

	Example:
		(start code)
			<button onclick="pax.widget.menu.tree.openAll(pax.$('pax.widget.menu.tree.example2'))">Open All</button>
			<button onclick="pax.widget.menu.tree.closeAll(pax.$('pax.widget.menu.tree.example2'));">Close All</button>
			<input type="text" id="searchBox" value="patrick roast brulee long scotch green" size="30">
			<button onclick="pax.widget.menu.tree.search(pax.$('pax.widget.menu.tree.example2'), pax.$('searchBox').value)">Search</button>
			<button onclick="pax.widget.menu.tree.clearSearch( pax.$('pax.widget.menu.tree.example2') );">Clear</button>
			<fieldset><legend>Tree menu</legend>
				<ul id="pax.widget.menu.tree.example2">
					<li>Entree
						<ul>
							<li><a>Garlic bread</a></li>
							<li><a>Oysters kilpatrick</a></li>
							<li><a>Mini Ceasar salad</a></li>
						</ul>
					</li>
					<li>Mains
						<ul>
							<li><a>Roast Lamb</a></li>
							<li><a>Grill Chicken</a></li>
							<li><a>Sirloin steak</a></li>
						</ul>
					</li>
					<li>Dessert
						<ul>
							<li><a>Chocolate mousse</a></li>
							<li><a>Creme brulee</a></li>
							<li>Coffee & tea
								<ul>
									<li><a>Long black</a></li>
									<li><a>Capuccino</a></li>
									<li><a>Latte</a></li>
									<li>Liquor coffes
										<ul>
											<li><a>Kaluah</a></li>
											<li><a>Tia Maria</a></li>
											<li><a>Frangelico</a></li>
											<li><a>Butter Scotch</a></li>
										</ul>
									</li>
									<li><a>English breakfast tea</a></li>
									<li><a>Japanese green tea</a></li>
									<li><a>camomile tea</a></li>
								</ul>
							</li>
							<li><a>Surprise of the day</a></li>
						</ul>
					</li>
				</ul>
			</fieldset>

			[:.
				pax.widget.menu.tree.init( pax.$("pax.widget.menu.tree.example2") );
			:]
		(end)
		This will show an extensive example, with all features enabled

*/
pax.widget.menu.tree.init = function( target, args ) {
	args = args || {};
	
	//	If we have a model, use it as the structure for the menu
	if( args.model ) {
		var tpl = "<ul>" + pax.widget.menu.initModel( args.model ) + "</ul>";
		pax.template.render( tpl, { target: target } );
		//	The "actual" target is the first UL in the "target", so we get it.
		var targetUls = target.getElementsByTagName('ul');
		target = targetUls[0];
	}
	
	pax.util.addClassName( target, 'paxMenuTree' );
	
	var uls = target.getElementsByTagName("ul");
	for( var i = 0; i < uls.length; i++ ) {
		pax.util.addClassName( uls[i].parentNode, 'submenu' );
		
		//	Workaround for IE - we MUST have layout for this to work
		if( pax.isIe ) {
			var lis = uls[i].getElementsByTagName("li");
			for( var x = 0; x < lis.length; x++ ) {
				if( ! lis[x].currentStyle.hasLayout )lis[x].style.zoom = 1;
			}
		}
		
		//	Assign a function for clicking on items
		pax.event.bind( uls[i].parentNode, 'click', function( e ) {
			//	Check if the nodeType is an LI, if not, don't do anything.
			var target = e.target || window.event.srcElement;
			if( target.nodeName.toUpperCase() == "LI" ) {
				pax.widget.menu.tree.toggleSubMenu( this );
			}
			pax.event.preventpropagate( e );
		} );

		//	Find last LI item, and add the 'last' classname
		var item = uls[i].lastChild;
		while( !item.tagName || item.tagName.toLowerCase() != "li" )item = item.previousSibling;
		pax.util.addClassName( item, 'last' );
	}

	//	Find last LI item, and add the 'last' classname
	var item = target.lastChild;
	while( !item.tagName || item.tagName.toLowerCase() != "li" )item = item.previousSibling;
	pax.util.addClassName( item, 'last' );
};


/*	Private Method: pax.widget.menu.tree.closeSubMenu
	Closes a sub menu
*/
pax.widget.menu.tree.closeSubMenu = function( branch ) {
	var submenu = branch.getElementsByTagName('ul')[0];
	submenu.style.display = 'none';
	pax.util.swapClassName( submenu, 'subMenuOpen', 'subMenuClosed' );		//	Set the identifying class
	pax.util.swapClassName( branch, 'menuOpen', 'menuClosed' );				//	Set the folder icon class
};


/*	Private Method: pax.widget.menu.tree.openSubMenu
	Opens a sub menu
*/
pax.widget.menu.tree.openSubMenu = function( branch ) {
	var submenu = branch.getElementsByTagName('ul')[0];
	submenu.style.display = 'block';
	pax.util.swapClassName( submenu, 'subMenuClosed', 'subMenuOpen' );		//	Set the identifying class
	pax.util.swapClassName( branch, 'menuClosed', 'menuOpen' );				//	Set the folder icon class
};


/*	Private Method: pax.widget.menu.tree.toggleSubMenu
	Toggles a sub menu
*/
pax.widget.menu.tree.toggleSubMenu = function( branch ) {
	var submenu = branch.getElementsByTagName('ul')[0];
	if( pax.util.hasClassName( submenu, 'subMenuOpen' ) ) {
		pax.widget.menu.tree.closeSubMenu( branch );
	} else {
		pax.widget.menu.tree.openSubMenu( branch );
	}
};


/*	Private Method: pax.widget.menu.tree.openAll
	Opens all sub menus
*/
pax.widget.menu.tree.openAll = function( element ) {
	var uls = element.getElementsByTagName("ul");
	for( var i = 0; i < uls.length; i++ ) {
		pax.widget.menu.tree.openSubMenu( uls[i].parentNode );
	}
};


/*	Private Method: pax.widget.menu.tree.closeAll
	Closes all sub menus
*/
pax.widget.menu.tree.closeAll = function( element ) {
	var uls = element.getElementsByTagName("ul");
	for( var i = 0; i < uls.length; i++ ) {
		pax.widget.menu.tree.closeSubMenu( uls[i].parentNode );
	}
};


/*	Private Method: pax.widget.menu.tree.search
	Searches a menu based on specified text, and changes the nodes that match to include 
	the 'highlight' CSS class
	
	TODO: Search in LIs that contain ULs
	*UPDATE* Turns out that it's actually working, BUT the LI already has a background image, which is blocking the colour
*/
pax.widget.menu.tree.search = function( element, text ) {
	pax.widget.menu.tree.closeAll( element );
	pax.widget.menu.tree.clearSearch( element );
	var texts = text.split(' ');	//	Split by space, so we can match all
	var lis = element.getElementsByTagName("li");
	for( var i = 0; i < lis.length; i++ ) {
		//	We make the string one line only, so indexOf can be used to check for the presence of our search string
		//	Note: this is matching everything, including surrounding LIs!!! <- causes an issue in IE (not FF though, as it's CSS is correct.)
		var liText = lis[i].innerHTML.toLowerCase().split('\n').join('').split('\r').join('');
		
		//	Check if the content matches, ignoring case.
		for( var t = 0; t < texts.length; t++ ) {
			var searchText = texts[t].toLowerCase();
			if( searchText != '' ) {
				if( liText.indexOf( searchText ) != -1 ) {
					pax.util.addClassName( lis[i], 'highlight' );
					if( lis[i].getElementsByTagName("ul").length > 0 )pax.widget.menu.tree.openSubMenu( lis[i] );
					break;
				}
			}
		}
	}
};


/*	Private Method: pax.widget.menu.tree.clearSearch
	Clears the node CSS highlight classes, from the search
*/
pax.widget.menu.tree.clearSearch = function( element ) {
	var lis = element.getElementsByTagName("li");
	for( var i = 0; i < lis.length; i++ ) {
		pax.util.removeClassName( lis[i], 'highlight' );
	}
};